> type Vector = (Int, Int, Int)
> type Point  = (Int, Int, Int)

У кубика рубика 6 граней, которые выкрашены в шесть цветов

> data Side = FrontS | BackS | LeftS | RightS | UpS | DownS deriving (Show, Enum)
> data Color = Red | Orange | Blue | Green | White | Yellow deriving (Show)

следующем образом

> color :: Side -> Color
> color FrontS = Blue
> color BackS = Green
> color LeftS = Red
> color RightS = Orange
> color UpS = White
> color DownS = Yellow

Грани кубика Рубика пусть будут ориентированы следующем образом

> sideOrientation :: Side -> Vector
> sideOrientation FrontS = (0, -1, 0)
> sideOrientation BackS  = (0, 1, 0)
> sideOrientation LeftS  = (-1, 0, 0)
> sideOrientation RightS = (1, 0, 0)
> sideOrientation UpS    = (0, 0, 1)
> sideOrientation DownS  = (0, 0, -1)

Обратное sideOrientation - есть

> sideOrientationI :: Vector -> Side
> sideOrientationI a = until (\x -> sideOrientation x == a) (succ) FrontS

Каждую грань можно вращать вокруг нормали к ней же по часовой стрелке на 90 градусов, 
против часовой стрелки на 90 градусов и на 180 градусов

> data Rotation = Clockwise | IClockwise | UTurn deriving (Show)

Опишем вращение вокруг шести осей функцией

> rotation :: Rotation -> Vector -> Vector -> Vector

Например вращение вокруг нормали к фронтальной грани FrontS по часовой стрелке - это
вращение вокруг вектора (0, -1, 0). Такое вращение будет менять компоненты вектора (x, y, z) 
на (z, y, -x). Как видим, компонента y не поменялась.
Кратко о вращении по часовой стрелки вокруг нормали v - это вращение против часовой стрелки 
вокруг нормали (-v). Таким образом

> rotation IClockwise v@(a, b, c) (x, y, z) | v == (1, 0, 0) = (x, -z, y)
>                                           | v == (0, 1, 0) = (z, y, -x)
>                                           | v == (0, 0, 1) = (-y, x, z)
>                                           | otherwise = (f . f . f) (x, y, z)
>     where f = rotation IClockwise (-a, -b, -c)
> rotation Clockwise (a, b, c) x = rotation IClockwise (-a, -b, -c) x 
> rotation UTurn v x = (f . f) x where f = rotation IClockwise v

Теперь можно описать вращения вокруг граней

> vecRotation :: Rotation -> Side -> Vector -> Vector
> vecRotation r s = rotation r (sideOrientation s) 

Опишем обратное вращение 

> vecRotationI r s = rotation r (-a, -b, -c) where (a, b, c) = sideOrientation s 

Кубик Рубика состоит из 26 маленьких кубиков. Вращения граней меняют координаты и ориентации 
маленьких кубиков. Таким образов положение маленького кубика определяется координатами центра
и ориентацией граней по отношению к ориентации граней Кубика Рубика.

> data Cube = Cube { coord :: Point,
>                    orientation :: Side -> Side
>                  } 

В начальной конфигурации все 26 кубиков можно представить, как

> rubikCube :: [Cube]
> rubikCube = map (g) [(x, y, z) | x <- [-1..1], y <- [-1..1], z <- [-1..1]] where
>     g (x,y,z) = Cube { coord = (x,y,z),
>                        orientation = id 
>                      }

Поворот маленького кубика опишем функцией

> cubeRotate :: Rotation -> Side -> Cube -> Cube
> cubeRotate r s c = Cube { coord = x',
>                           orientation = f' } where
>     x' = vecRotation r s (coord c)
>     f' = sideOrientationI . (vecRotationI r s) . sideOrientation . (orientation c)

Поворот Кубика Рубика опишем так

> rotateRubikCube :: Rotation -> Side -> [Cube] -> [Cube]
> rotateRubikCube r s c = map (g) c where
>     g x | (coord x) `scalar` (sideOrientation s) > 0 = cubeRotate r s x
>         | otherwise = x

> scalar :: Vector -> Vector -> Int
> scalar (x0, y0, z0) (x1, y1, z1) = x0*x1 + y0*y1 + z0*z1

Теперь отрисуем кубик на экране функцией

